package org.akomantoso.core.data;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.akomantoso.core.data.attribute.Core;
import org.akomantoso.core.data.attribute.IdOpt;
import org.akomantoso.core.data.attribute.LinkOpt;
import org.akomantoso.core.io.Externalizable;
import org.akomantoso.core.io.Input;
import org.akomantoso.core.io.Output;
import org.akomantoso.core.io.OutputUtil;

/**
 * the complex type anyOtherType defines an open content model for elements that may use elements from other namespaces.
 * 
 * <pre>
 * 	<xsd:complexType name="anyOtherType">
 * 		<xsd:choice>
 * 			<xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
 * 		</xsd:choice>
 * 		<xsd:attributeGroup ref="core"/>
 * 		<xsd:attributeGroup ref="idopt"/>
 * 		<xsd:attributeGroup ref="linkopt"/>
 * 	</xsd:complexType>
 * </pre>
 * 
 * @author <a href="mailto:jacques.militello@gmail.com">Jacques Militello</a>
 * 
 * @since http://www.akomantoso.org/1.0
 */
public class AnyOtherType implements IdOpt, LinkOpt, Core, Externalizable {

	private String _id;
	private String _evolvingId;
	private String _href;

	private List<AnyOtherTypeElement> _others;

	private Map<String,String> _namespaces;
	
	/**
	 * @see org.akomantoso.core.data.attribute.IdOpt#getId()
	 */
	@Override
	public String getId() {
		return _id;
	}

	/**
	 * @see org.akomantoso.core.data.attribute.IdOpt#setId(java.lang.String)
	 */
	@Override
	public void setId(String id) {
		_id = id;
	}

	/**
	 * @see org.akomantoso.core.data.attribute.IdOpt#getEvolvingId()
	 */
	@Override
	public String getEvolvingId() {
		return _evolvingId;
	}

	/**
	 * @see org.akomantoso.core.data.attribute.IdOpt#setEvolvingId(java.lang.String)
	 */
	@Override
	public void setEvolvingId(String evolvingId) {
		_evolvingId = evolvingId;
	}

	/**
	 * @see org.akomantoso.core.data.attribute.LinkOpt#getHref()
	 */
	public String getHref() {
		return _href;
	}

	/**
	 * @see org.akomantoso.core.data.attribute.LinkOpt#setHref(java.lang.String)
	 */
	public void setHref(String href) {
		_href = href;
	}

	/**
	 * @return the others
	 */
	public List<AnyOtherTypeElement> getOthers() {
		return _others;
	}

	/**
	 * @param others
	 *            the others to set
	 */
	public void setOthers(List<AnyOtherTypeElement> others) {
		_others = others;
	}

	public void addOtherElement(AnyOtherTypeElement other) {
		if (_others == null) {
			_others = new ArrayList<AnyOtherTypeElement>();
		}
		_others.add(other);
	}

	/**
	 * @see org.akomantoso.core.io.Externalizable#writeExternal(org.akomantoso.core.io.Output)
	 */
	public <T extends Output> void writeExternal(T out) throws IOException {
		OutputUtil.writeLinkOpt(out, this);
		OutputUtil.writeIdOpt(out, this);
		if (_namespaces != null) {
			for (String key : _namespaces.keySet()) {
				out.writeAttribute(new StringBuilder().append("xmlns:").append(key).toString(), _namespaces.get(key));
			}
		}
		if (_others != null) {
			for (int i = 0 , n = _others.size() ; i < n ; i++) {
				_others.get(i).writeExternal(out);
			}
		}
	}

	/**
	 * @see org.akomantoso.core.io.Externalizable#readExternal(org.akomantoso.core.io.Input)
	 */
	public <T extends Input> void readExternal(T in) throws IOException {
		_href = in.readAttribute(LinkOpt.ATTRIBUTE);
		_id = in.readAttribute(IdOpt.ATTRIBUTE_ID);
		_evolvingId = in.readAttribute(IdOpt.ATTRIBUTE_EVOLVING_ID);
		in.readExternal(this);
	}

	public void addNamespace(String namespacePrefix, String namespaceURI) {
		if (_namespaces == null) {
			_namespaces = new HashMap<String, String>(4);
		}
		_namespaces.put(namespacePrefix, namespaceURI);
	}

}